"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".

Replace this with more appropriate tests for your application.
"""
from datetime import date
import datetime
from django.contrib.auth.models import User

from django.test import TestCase
from django.test.client import RequestFactory, Client
from opengoal import views
from opengoal.models import Goal, EntityTag, Task, Tag, Journal
from opengoal.templatetags.goal_extras import time_left, percentage
from opengoal.views import save_tags


class SimpleTest(TestCase):
    def setUp(self):
        self.factory = RequestFactory()
        self.client = Client()
        User.objects.all().delete()
        Goal.objects.all().delete()
        self.user = User.objects.create_user('asd', 'asd@asd.com', 'asd')
        self.client.login(username='asd', password='asd')

    def test_tag_splitter(self):
        tags = views.split_tags("a,b c, d,     e, f")
        good = ['a', 'b c', 'd', 'e', 'f']
        self.assertEqual(len(tags), 5)
        def check(val):
            self.assertTrue(val in good )
            good.remove(val)
        for val in tags:
            check(val)

    def test_tag_splitter_exclude_same(self):
        tags = views.split_tags("a,a, aa, b")
        good = ['a', 'aa', 'b']
        self.assertEqual(len(tags), 3)
        def check(val):
            self.assertTrue(val in good )
            good.remove(val)
        for val in tags:
            check(val)

    def test_add_goal_unbound(self):
        """
        The start_date should be filled with the actual date in an empty form
        """
        response = self.client.get('/goals/add/')
        #self.assertEqual(response.context['form'].fields['start_date'], date.today().isoformat())

    def test_add_goal(self):
        params = {
            'name': 'Start my own business',
            'description': 'Test',
            'start_date': '2012-07-10',
            'due_date': '2012-07-11',
            'categories': 'a,b,c',
            'show_on_dashboard': 'True',
            }
        self.assertEqual(len(Goal.objects.all()), 0)
        response = self.client.post('/goals/add/', params)
        self.assertEqual(len(Goal.objects.all()), 1)
        goal = Goal.objects.all()[0]
        self.assertEqual(goal.name, 'Start my own business')
        self.assertEqual(goal.description, 'Test')
        self.assertEqual(goal.start_date, datetime.date(2012, 07, 10))
        self.assertEqual(goal.due_date, datetime.date(2012, 07, 11))
        self.assertEqual(len(goal.category_set.all()), 3)
        self.assertEqual(goal.show_on_dashboard, True)

        self.assertRedirects(response, '/goals/')

        self.assertEqual(len(self.user.goal_set.all()), 1)

    def test_delete_goal(self):
        goal = Goal.objects.create(name="test", start_date=datetime.datetime.now())
        self.assertEqual(len(Goal.objects.all()), 1)
        response = self.client.post('/goals/delete/1/')
        self.assertEqual(len(Goal.objects.all()), 0)
        self.assertRedirects(response, '/goals/')

    def test_edit_goal(self):
        params = {
            'name': 'modified',
            'description': 'Test',
            'start_date': '2012-07-10',
            'due_date': '2012-07-11',
            'categories': 'a,b,c',
            'show_on_dashboard': 'True',
            'goal': '1',
            }
        goal = Goal.objects.create(name="test", start_date=datetime.datetime.now())
        self.assertEqual(len(Goal.objects.all()), 1)
        response = self.client.post('/goals/', params)
        self.assertEqual(len(Goal.objects.all()), 1)
        goal = Goal.objects.all()[0]
        self.assertEqual(goal.name, 'modified')
        self.assertEqual(goal.description, 'Test')
        self.assertEqual(goal.start_date, datetime.date(2012, 07, 10))
        self.assertEqual(goal.due_date, datetime.date(2012, 07, 11))
        self.assertEqual(len(goal.category_set.all()), 3)
        self.assertEqual(goal.show_on_dashboard, True)

        self.assertEqual(len(self.user.goal_set.all()), 1)

    def test_save_new_tags(self):
        self.assertEqual(len(Tag.categories(self.user)), 0)
        Tag.journal_tag('a', self.user).save()
        Tag.journal_tag('b', self.user).save()
        self.assertEqual(len(Tag.journal_tags(self.user)), 2)
        views.save_new_tags(['a', 'b', 'c', 'd'], Tag.journal_tags(self.user), Tag.journal_tag, self.user)
        self.assertEqual(len(Tag.journal_tags(self.user)), 4)
        tags = [tag.name for tag in Tag.journal_tags(self.user)]
        self.assertEqual(tags, ['a', 'b', 'c', 'd'])

    def test_time_away(self):
        tomorrow = datetime.date.today() + datetime.timedelta(days=1)
        goal = Goal(name="test", start_date=datetime.datetime(2012, 1, 1), due_date=tomorrow)
        self.assertEqual(time_left(goal), "1 days away")

        next_motnth = datetime.date.today() + datetime.timedelta(days=33)
        goal = Goal(name="test", start_date=datetime.datetime(2012, 1, 1), due_date=next_motnth)
        self.assertEqual(time_left(goal), "1 months away")

        next_year = datetime.date.today() + datetime.timedelta(days=400)
        goal = Goal(name="test", start_date=datetime.datetime(2012, 1, 1), due_date=next_year)
        self.assertEqual(time_left(goal), "1 years away")

    def test_goal_percentage_divide_by_zero(self):
        goal = Goal(name="test", start_date=datetime.datetime(2012, 1, 1))
        self.assertEqual(percentage(goal), r"0%")

    def test_goal_percentage(self):
        goal = Goal(name="test", start_date=datetime.datetime(2012, 1, 1))
        task1 = Task.objects.create(start_date=datetime.datetime.now())
        task2 = Task.objects.create(start_date=datetime.datetime.now())
        task3 = Task.objects.create(start_date=datetime.datetime.now())
        task4 = Task.objects.create(start_date=datetime.datetime.now())

        self.assertEqual(percentage(goal), r"0%")
        task1.completed_date = datetime.datetime.now()
        task1.save()
        self.assertEqual(percentage(goal), "25%")
        task2.completed_date = datetime.datetime.now()
        task2.save()
        self.assertEqual(percentage(goal), "50%")
        task3.completed_date = datetime.datetime.now()
        task3.save()
        self.assertEqual(percentage(goal), "75%")
        task4.completed_date = datetime.datetime.now()
        task4.save()
        self.assertEqual(percentage(goal), "100%")

    def sub_test_journal(self, response, goal):
        self.assertEqual(len(Journal.objects.all()), 1)
        journal = Journal.objects.get(pk=1)
        self.assertEqual(journal.goal, goal)
        self.assertEqual(journal.title, 'Test title')
        self.assertEqual(journal.content, 'Test content')
        self.assertEqual(journal.created_date.day, datetime.datetime.now().day)
        self.assertEqual(journal.last_mod.day, datetime.datetime.now().day)
        self.assertEqual(journal.user, self.user)

        self.assertRedirects(response, '/journals/')

        self.assertEqual(len(Tag.journal_tags(self.user).all()), 3)
        self.assertEqual(len(self.user.journal_set.all()), 1)

    def test_add_journal(self):
        params = {
            'title': 'Test title',
            'content': 'Test content',
            'tags': 'a,b,c',
            }
        self.assertEqual(len(Journal.objects.all()), 0)
        self.assertEqual(len(Tag.journal_tags(self.user).all()), 0)
        response = self.client.post('/journals/edit/', params)
        self.sub_test_journal(response, None)

    def test_add_goal_journal(self):
        goal = Goal.objects.create(name="test", start_date=datetime.datetime.now())
        params = {
            'goal': goal.pk,
            'title': 'Test title',
            'content': 'Test content',
            'tags': 'a,b,c',
            }
        self.assertEqual(len(Journal.objects.all()), 0)
        self.assertEqual(len(Tag.journal_tags(self.user).all()), 0)
        response = self.client.post('/journals/edit/', params)
        self.sub_test_journal(response, goal)

    def test_edit_journal(self):
        goal = Goal.objects.create(name="test", start_date=datetime.datetime.now())

        tag1 = Tag.journal_tag('a', self.user)
        tag1.save()
        tag2 = Tag.journal_tag('b', self.user)
        tag2.save()

        journal = Journal.objects.create(title='a', content='b', user=self.user)
        journal.save()
        journal_id = journal.pk
        EntityTag(entity_id=journal_id, tag=tag1).save()
        EntityTag(entity_id=journal_id, tag=tag2).save()
        params = {
            'for_goal_id': goal.pk,
            'title': 'A',
            'content': 'B',
            'tags': 'a',
            }
        self.assertEqual(len(Journal.objects.all()), 1)
        self.assertEqual(len(Tag.journal_tags(self.user).all()), 2)
        self.assertEqual(len(journal.tag_set.all()), 2)
        response = self.client.post('/journals/edit%d/' % journal_id, params)
        self.assertEqual(len(Journal.objects.all()), 1)
        journal = Journal.objects.get(pk=journal_id)
        self.assertEqual(journal.title, 'A')
        self.assertEqual(journal.content, 'B')
        self.assertEqual(len(Tag.journal_tags(self.user).all()), 2)
        self.assertEqual(len(journal.tag_set.all()), 1) # a, b -> a


    def test_edit_journal_same_tags(self):
        journal = Journal.objects.create(title='a', content='b', user=self.user)
        journal.save()
        params = {
            'title': 'A',
            'content': 'B',
            'tags': 'a, a',
            }
        self.assertEqual(len(journal.tag_set.all()), 0)
        response = self.client.post('/journals/edit%d/' % journal.pk, params)
        self.assertEqual(len(journal.tag_set.all()), 1)


    def test_add_goal_tags(self):
        """
        One tag should be saved only once for an entity
        """
        journal = Journal.objects.create(title='a', content='b', user=self.user)
        tag = Tag.journal_tag('a', self.user)
        tag.save()
        self.assertEqual(len(EntityTag.journal_tags(journal)), 0)
        save_tags(self.user, ['a'], 'JOURNAL', self.user)
        self.assertEqual(len(EntityTag.journal_tags(journal)), 1)
        save_tags(self.user, ['a'], 'JOURNAL', self.user)
        self.assertEqual(len(EntityTag.journal_tags(journal)), 1)

    def test_delete_journal(self):
        journal = Journal.objects.create(title="test", content='asd', user=self.user)
        self.assertEqual(len(Journal.objects.all()), 1)
        response = self.client.post('/journals/delete/1/')
        self.assertEqual(len(Journal.objects.all()), 0)
        self.assertRedirects(response, '/journals/')

    def test_journal_empty_goal(self):
        response = self.client.get('/journals/?goal=') # it shouldn't throw any exception

    def test_add_sub_goal(self):
        parent = Goal.objects.create(name="test")
        params = {
            'name': 'Start my own business',
            'description': 'Test',
            'due_date': '2012-07-11',
            'show_on_dashboard': 'True',
            'parent': '1',
            }
        self.assertEqual(len(Goal.objects.all()), 1)
        self.assertEqual(len(parent.goal_set.all()), 0)
        response = self.client.post('/goals/add/', params)
        self.assertEqual(len(Goal.objects.all()), 2)
        goal = Goal.objects.all()[1]
        self.assertEqual(goal.name, 'Start my own business')
        self.assertEqual(goal.description, 'Test')
        self.assertEqual(goal.due_date, datetime.date(2012, 07, 11))
        self.assertEqual(goal.show_on_dashboard, True)
        self.assertEqual(goal.parent, parent)

        self.assertRedirects(response, '/goals/')
        self.assertEqual(len(parent.goal_set.all()), 1)

    def test_add_task(self):
        goal = Goal.objects.create(name="test")
        params = {
            'name': 'Start my own business',
            'note': 'Test',
            'due_date': '2012-07-11',
            'show_on_dashboard': 'True',
            'goal': '1',
            'estimated_time': '0:30',
            }
        self.assertEqual(len(Task.objects.all()), 0)
        self.assertEqual(len(goal.task_set.all()), 0)
        response = self.client.post('/tasks/', params)
        self.assertEqual(len(Task.objects.all()), 1)
        self.assertEqual(len(goal.task_set.all()), 1)
        task = Task.objects.all()[0]
        self.assertEqual(task.name, 'Start my own business')
        self.assertEqual(task.note, 'Test')
        self.assertEqual(task.due_date, datetime.date(2012, 07, 11))
        self.assertEqual(task.spent_time, datetime.time(0, 0))
        self.assertEqual(task.estimated_time, datetime.time(0, 30))
        self.assertEqual(task.recurring, None)

        self.assertRedirects(response, '/tasks%s/' % goal.pk)

    def test_modify_task(self):
        goal = Goal.objects.create(name="test")
        task = Task.objects.create(name='a', note='b', goal=goal)
        self.assertEqual(len(Task.objects.all()), 1)
        self.assertEqual(len(goal.task_set.all()), 1)

        params = {
            'name': 'Start my own business',
            'note': 'Test',
            'due_date': '2012-07-11',
            'show_on_dashboard': 'True',
            'goal': '1',
            'task': task.pk ,
            'estimated_time': '0:30',
            }
        response = self.client.post('/tasks/', params)
        self.assertEqual(len(Task.objects.all()), 1)
        self.assertEqual(len(goal.task_set.all()), 1)
        task = Task.objects.all()[0]
        self.assertEqual(task.name, 'Start my own business')
        self.assertEqual(task.note, 'Test')
        self.assertEqual(task.due_date, datetime.date(2012, 07, 11))
        self.assertEqual(task.spent_time, datetime.time(0, 0))
        self.assertEqual(task.estimated_time, datetime.time(0, 30))
        self.assertEqual(task.recurring, None)

        self.assertRedirects(response, '/tasks%s/' % goal.pk)

    def test_empty_task_id(self):
        goal = Goal.objects.create(name="test")
        params = {
            'name': 'Start my own business',
            'note': 'Test',
            'due_date': '2012-07-11',
            'show_on_dashboard': 'True',
            'goal': '1',
            'task': '',
            'estimated_time': '0:30',
            }
        self.assertEqual(len(Task.objects.all()), 0)
        self.assertEqual(len(goal.task_set.all()), 0)
        response = self.client.post('/tasks/', params)
        self.assertEqual(len(Task.objects.all()), 1)
        self.assertEqual(len(goal.task_set.all()), 1)
        task = Task.objects.all()[0]
        self.assertEqual(task.name, 'Start my own business')
        self.assertEqual(task.note, 'Test')
        self.assertEqual(task.due_date, datetime.date(2012, 07, 11))
        self.assertEqual(task.spent_time, datetime.time(0, 0))
        self.assertEqual(task.estimated_time, datetime.time(0, 30))
        self.assertEqual(task.recurring, None)

        self.assertRedirects(response, '/tasks%s/' % goal.pk)

    def test_delete_task(self):
        goal = Goal.objects.create(name="test")
        task = Task.objects.create(name='a', note='b', goal=goal)
        self.assertEqual(len(Task.objects.all()), 1)
        response = self.client.post('/tasks/delete/%s/' % task.pk)
        self.assertEqual(len(Task.objects.all()), 0)
        self.assertRedirects(response, '/tasks%s/' % goal.pk)